#!/usr/bin/python
import bot
import dict4ini
import sys
import code
import traceback
import signal
import platform
#import gui

from ini import *
from utils import *
#from Tkinter import *

def log(*args):
	"Replacement for print, which doesn't deal with unicode well"
	userText = None
	if len(args) > 1:
		userText = args[1]
	if userText and len(userText) > 4 and userText[0:5] == '[off]':
		return
	
	msg=u" ".join(map(unicode,args))
	# Replace unencodable charactors with ?
	print >>bot.logf, time.strftime("%Y-%m-%d %H:%M:%S"), msg.encode("utf_8","replace")
	bot.logf.flush()
	print time.strftime("%H:%M:%S"), msg.encode("iso8859_2","replace")
	
#Command "RAISE" exception classes	
class COMMAND_HELP(Exception):pass	
	
class ConferenceBot(bot.Bot):
	def __init__(self):
		global config
	
		#Define .ini lists
		config = cbot2
		self.config = cbot2
		
		#Start all the behind the scenes functions.
		bot.Bot.__init__(self,
			core.required.username,
			core.required.password)
			
		#Plugin hashing dictionary
		self.pluginhash = {}
		
		#Define command dictionarys.
		self.commands = {}
		self.modcommands = {}
		self.admincommands = {}
		self.mutecommands = {}
		self.hooks = {}
		
		#Core settings are module independant and should be loaded first.
		readcore(self)
		core.required.module = "cbot2" #Set currently used module.
		savecore()
		
		#Load all bot settings.
		readall()
		saveall()
		
		#if config.static.gui == "Three Bacon Hogs":
		#	root = Tk()
		#	
		#	self.gui = gui.GUI(root)
		#	
		#	root.mainloop()
		
		self.pluglog = file(os.path.join("errors", "PluginError.log"), "a+")
		#Load all external plugins and warn the user about missing plugins.
		for i in config.system.plugins.split(" "):
			try:	
				a = open(os.path.join("plugins","plugin_%s.py") % i,"r").read()
				plugin = {}
				exec a in plugin
				debug(2,"Loading plugin %s" % i)
				plugin["init"](self)
				self.pluginhash[i] = hash(a)
			except IOError:
				print 'The plugin "plugin_%s.py" could not be found.' % i
				continue
			except:
				traceback.print_exc()
				print >>self.pluglog, "\n"
				traceback.print_exc(None, self.pluglog)
				self.pluglog.close()
				print 'There was an error importing the plugin. A report has been logged.'
				continue

	def log(self,*args):
		log(*args)

	def addCommand(self,name,command):
		self.commands[name] = command

	def addModCommand(self,name,command):
		self.modcommands[name] = command
		
	def addAdminCommand(self,name,command):
		self.admincommands[name] = command
		
	def addMuteCommand(self, name, command):
		self.mutecommands[name] = command
		
	def addHook(self,name,command):
		if name in self.hooks:
			self.hooks[name].append(command)
		else:
			self.hooks[name] = [command]

	def hook(self,name,*args):
		# Multiple plugins can register hooks, the first one to
		# return True causes all further processing of that hook
		# to be aborted.
		if name in self.hooks:
			for hook in self.hooks[name]:
				if hook(self,args):
					return False

	def command(self,user,msg):
		if " " in msg:
			cmd,args = msg.split(" ",1)
		else:
			cmd,args = msg.strip().lower(),""
		try:
			if ismuted(user):
				if cmd in self.mutecommands:
					func = self.mutecommands[cmd]
					func(self,user,args)
			elif cmd in self.commands:
				func = self.commands[cmd]
				func(self,user,args)
			elif cmd in self.modcommands:
				if ismod(user) or isadmin(user):
					func = self.modcommands[cmd]
					func(self,user,args)
				else:
					self.error(user, "You must be a moderator to use that command.")
			elif cmd in self.admincommands:
				if isadmin(user):
					func = self.admincommands[cmd]
					func(self,user,args)
				else:
					self.error(user,"You must be an admin to use that command.")
			else:
				self.error(user,"Unknown command, try )help")
		except COMMAND_HELP:
			self.sys(user, func.__doc__)
					
	def sendtoall(self,msg,butnot=[],name=""):
		for user in self.getRoster():
			# Skip any users in butnot
			if unicode(user) in butnot:
				continue
			for resource,(status,display) in self.getJidStatus(user).items(): 
				# Ignore people who aren't online
				if status in [u"online",u"chat"] and not isaway(getjid(resource)):
					if name:
						format = getformat(user, "main", u'<*%(name)s*> %(msg)s')
					else:
						format = u'%(msg)s'
					self.msg(resource, format % {"name":name,"msg":msg})
					
	def sys(self,user,msg):
		self.msg(user, config.system.sysprefix + " " + msg)
	
	def systoall(self,msg,butnot=[]):
		self.sendtoall(config.system.sysprefix + " " + msg, butnot)
	
	def error(self,user,msg):
		"Send an error message to a user"
		self.msg(user,"ERROR: " + msg)
		
			
	def ev_msg(self,user,msg):
		# Is this a command?
		if msg[:1] in config.system.commandprefix:
			self.command(user,msg[1:])
		elif getjid(user) != getjid(core.required.username):
			msg = clean_string(msg)
			msg = autocomplete(msg)
			
			self.log("<"+getdisplayname(user)+">",msg)
			
			#Update when the user last sent a message.
			set_userflag(user,"last msg", time.time())

			if not self.hook("message",user,msg):
				self.sendtoall(msg,butnot=[unicode(user.getStripped())], name=unicode(getdisplayname(user)))

	def ev_unsubscribe(self,user,msg):
		# User removed us from their list
		# So remove them from ours.
		log(user,"unsubscribing:",msg)
		del userlist[user]
		self.removeUser(user)
		self.rejectUser(user)

	def ev_unsubscribed(self,user,msg):
		# User has forced us to remove them from our list
		log(user,"unsubscribing:",msg)
		del userlist[user]
		self.removeUser(user)
		self.rejectUser(user) # Remove us from their list

	def ev_subscribe(self,user,msg):
		if isbanned(user):
			self.rejectUser(user)
		else:
			# User added us to their list, so add them to ours
			log(user,"subscribing:",msg)
			self.addUser(user)
			self.acceptUser(user)

        def ev_online(self, user, msg):
            #Update the last time a user was online.			
            set_userflag(user,"last login", time.time())
            #if not isaway(getjid(user)):
	        #self.sendtoall(u'user %(name)s has come online' % { "name" : getdisplayname(user) })

        #def ev_unavailable(self, user, msg):
            #self.sendtoall(u'user %(name)s has gone off-line' % { "name" : getdisplayname(user) })
		
def debugg(sig, frame):
    d={'_frame':frame}
    d.update(frame.f_globals)
    d.update(frame.f_locals)
    
    i=code.InteractiveConsole(d)
    message="Signal received: entering python shell.\nTraceback:\n"
    message += ''.join(traceback.format_stack(frame))
    i.interact(message)
    
def listen():
    signal.signal(signal.SIGUSR1, debugg)
    
def startBot():
    sysName = platform.system()
    sysName = sysName.lower()
    if 'windows' != sysName:
        listen()
    sys.setdefaultencoding('utf-8')
    me = ConferenceBot()
    me.connect(("talk.google.com",5223), use_srv = False, resource = 'conference')
    me.setOnline(module.system.status)

    #Add any new users.
    for i in me.getRoster():
        i = getjid(i)
        if i not in userlist.keys():
            adduser(getcleanname(i))
		
    debug(1,"The bot is now online!\nRunning version: %s\nAt %s" % (77, time.strftime("%Y-%m-%d %H:%M:%S")))
    me.run()
    
if __name__ == "__main__":
    startBot()